package it.polimi.digitalstate.manager;

import java.sql.Date;

import it.polimi.digitalstate.dto.CitizenDTO;
import it.polimi.digitalstate.dto.JoinVoteDTO;
import it.polimi.digitalstate.dto.JoinrequestDTO;
import it.polimi.digitalstate.dto.MembershipDTO;
import it.polimi.digitalstate.dto.PartyDTO;
import it.polimi.digitalstate.entities.Citizen;
import it.polimi.digitalstate.entities.Election;
import it.polimi.digitalstate.entities.JoinVote;
import it.polimi.digitalstate.entities.Joinrequest;
import it.polimi.digitalstate.entities.Membership;
import it.polimi.digitalstate.entities.Party;

import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import managerexception.CannotSendJoinRequest;
import managerexception.CannotSendJoinVote;
import managerexception.CannotSubmitMembership;

/**
 * Session Bean implementation class MembershipManager
 */
@Stateless
public class MembershipManager implements MembershipManagerLocal {

	@PersistenceContext
	private EntityManager em;
	
    public MembershipManager() {
        // TODO Auto-generated constructor stub
    }
	@RolesAllowed({"citizen"})
	@Override
	public JoinrequestDTO getMembershipRequest(CitizenDTO citizen) {
		// TODO Auto-generated method stub
		return null;
	}
	@RolesAllowed({"citizen"})
	public JoinrequestDTO getMembershipRequest(int id) {
		
		Query q = em.createNamedQuery("joinrequest_getByID");
		q.setParameter("id",id);
		return (JoinrequestDTO) ((Joinrequest)q.getResultList().get(0)).getDTO();
	}
	@RolesAllowed({"citizen"})
	@Override
	public boolean isMembershipRequester(CitizenDTO citizen) {
		//TODO
		return PreconditionCheck.hasPendingRequest(citizen, em);
	}
	@RolesAllowed({"citizen"})
	@Override
	public void submitRequest(JoinrequestDTO membershiprequest) throws  CannotSendJoinRequest  {	
		if(PreconditionCheck.canRequestParty( membershiprequest.getCitizen(), em)){
		
		em.persist(
				new Joinrequest(
						(Party)DTOEntityTransformer.getEntity(em, membershiprequest.getParty()),
						(Citizen)DTOEntityTransformer.getEntity(em, membershiprequest.getCitizen()),
						PreconditionCheck.getCurrentElection(em),
						membershiprequest.getCv(),
						membershiprequest.getLetter(),
						new Date((new java.util.Date()).getTime())
						)
				);
		}else{
			throw new CannotSendJoinRequest();
		}
	}
	@RolesAllowed({"citizen"})
	@Override
	public void voteRequest(CitizenDTO citizen,
			JoinrequestDTO membershiprequest, boolean positive) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public JoinrequestDTO[] getJoinrequestFromParty(CitizenDTO citizen, PartyDTO party) {
		Query q = em.createNamedQuery("joinrequest_getAllByParty");
		q.setParameter("party", DTOEntityTransformer.getEntity(em, party));
		Object[] o = q.getResultList().toArray();
		JoinrequestDTO[] ret = new JoinrequestDTO[o.length];
		for(int i=0;i<o.length;i++)
			ret[i]=(JoinrequestDTO) ((Joinrequest)o[i]).getDTO();
		return ret;
	}
    
	@SuppressWarnings("unused")
	private void acceptRequest(JoinrequestDTO request){
		//TODO implement @Mohamed
	}
	@SuppressWarnings("unused")
	private void denyRequest(JoinrequestDTO request){
		//TODO implement @Mohamed
	}

	@Override
	public boolean canRequest(CitizenDTO citizen) {
		// TODO Auto-generated method stub
		return PreconditionCheck.canRequestParty(citizen, em);
	}
	
	// methods for JoinVote
	public boolean hasAlreadyJoinVoted(CitizenDTO citizen, JoinrequestDTO joinrequest) {
		return !PreconditionCheck.canJoinVote( citizen, joinrequest, em);
	}
	
	@Override
	public void submitJoinVote(JoinVoteDTO joinvote) throws  CannotSendJoinVote {
		if(!hasAlreadyJoinVoted(joinvote.getCitizen(), joinvote.getJoinrequest()) && candidacyIsOpen() && !PreconditionCheck.isAMember(joinvote.getJoinrequest().getCitizen(), em)){
		
			em.persist(
					new JoinVote(
							(Citizen)DTOEntityTransformer.getEntity(em, joinvote.getCitizen()),
							(Joinrequest)DTOEntityTransformer.getEntity(em, joinvote.getJoinrequest()),
							joinvote.getApproval()
							)
					);
			}else{
				throw new CannotSendJoinVote();
			}
	}  
	
	@Override
	public boolean candidacyIsOpen(){
		return PreconditionCheck.rightCandidacyTime(em);
	}
	
	@Override
	public int governorEndCandidacy() throws CannotSubmitMembership {
		int numberAdded =0;
		Query q = em.createNamedQuery("joinrequest_getByElection");
		q.setParameter("election", PreconditionCheck.getCurrentElection(em));
		Object[] o = q.getResultList().toArray();
		JoinrequestDTO[] ret = new JoinrequestDTO[o.length];
		for(int i=0;i<o.length;i++)
			{
				ret[i]=(JoinrequestDTO) ((Joinrequest)o[i]).getDTO();
				Query a = em.createNamedQuery("joinvote_getcountofjoinrequest");
				a.setParameter("joinrequest",DTOEntityTransformer.getEntity(em, ret[i]) );
				a.setParameter("approval", true);
				Object[] c = a.getResultList().toArray();
				Long App_count = (Long) c[0];
				Query b = em.createNamedQuery("membership_getNumberofcurrentMembersFromParty");
				b.setParameter("party",DTOEntityTransformer.getEntity(em, ret[i].getParty()));
				Object[] d = b.getResultList().toArray();
				Long Mem_count = (Long) d[0];
				if(App_count > Mem_count/2)
				{
					MembershipDTO membership = new MembershipDTO(ret[i].getCitizen(), ret[i].getParty(), new  Date(new java.util.Date().getTime()),ret[i].getCv());
					try {createMembership(membership); numberAdded++;}
					catch(CannotSubmitMembership e) { /*throw new CannotSubmitMembership(numberAdded);*/}
				}
				a = null;
				b = null;
			}
		return numberAdded;
	}
	
	@Override
	public void createMembership(MembershipDTO membership) throws CannotSubmitMembership {	
		if(!PreconditionCheck.isAMember(membership.getCitizen(),em)){
		
		em.persist(
				new Membership(
						(Citizen)DTOEntityTransformer.getEntity(em, membership.getCitizen()),
						(Party)DTOEntityTransformer.getEntity(em, membership.getParty()),
						membership.getCv(),
						new java.sql.Date(membership.getDate_of_joining().getTime()),
						(membership.getDate_of_leaving()==null)?null:new java.sql.Date(membership.getDate_of_leaving().getTime())
						)
				);
		}else{
			throw new CannotSubmitMembership();
		}
	}
	
	@Override
	public boolean canJoinVote(CitizenDTO citizen, JoinrequestDTO joinrequest) {
		return (!hasAlreadyJoinVoted(citizen, joinrequest) && candidacyIsOpen() && !PreconditionCheck.isAMember(joinrequest.getCitizen(), em));
			
		}
		
}